package com.njtoyo.taxi.admin.service.business.driver.impl;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ReUtil;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.njtoyo.taxi.admin.cache.PrimaryCachePutter;
import com.njtoyo.taxi.admin.library.taxi_service.TaxiService;
import com.njtoyo.taxi.admin.logic.business.driver.DriverRegionServiceArrangementLogic;
import com.njtoyo.taxi.admin.logic.business.driver.ScoreDeductingLogLogic;
import com.njtoyo.taxi.admin.mapper.master.entity.Driver;
import com.njtoyo.taxi.admin.mapper.master.entity.DriverScoreDeducting;
import com.njtoyo.taxi.admin.mapper.master.entity.DriverScoreLog;
import com.njtoyo.taxi.admin.mapper.master.entity.Taxi;
import com.njtoyo.taxi.admin.mapper.master.enums.DriverRegionServiceArrangementCategory;
import com.njtoyo.taxi.admin.mapper.master.enums.DriverScoreDeductingCategory;
import com.njtoyo.taxi.admin.mapper.master.enums.DriverScoreLogCategory;
import com.njtoyo.taxi.admin.mapper.master.enums.DriverScoreLogInOut;
import com.njtoyo.taxi.admin.mapper.master.mapper.*;
import com.njtoyo.taxi.admin.mongo.entity.secondary.AdminDeductDriverScoreLogMongo;
import com.njtoyo.taxi.admin.mongo.repository.secondary.AdminDeductDriverScoreLogMongoRepository;
import com.njtoyo.taxi.admin.rest.presenter.business.driver.ScoreDeductingPresenter;
import com.njtoyo.taxi.admin.rest.presenter.platfrom.AdminUserIdentityPresenter;
import com.njtoyo.taxi.admin.rest.wrapper.business.driver.ScoreDeductingCreateWrapper;
import com.njtoyo.taxi.admin.rest.wrapper.business.driver.ScoreDeductingLogQueryDto;
import com.njtoyo.taxi.admin.rest.wrapper.business.driver.ScoreDeductingLogQueryWrapper;
import com.njtoyo.taxi.admin.rest.wrapper.business.driver.ScoreDeductingQueryWrapper;
import com.njtoyo.taxi.admin.service.business.driver.DriverScoreDeductingService;
import com.njtoyo.taxi.entity.backend.AdminUser;
import com.taxi.entity.common.RestResult;
import com.taxi.entity.common.ResultEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
@Slf4j
public class DriverScoreDeductingServiceImpl implements DriverScoreDeductingService {
    @Autowired
    private DriverRegionServiceArrangementMapper driverRegionServiceArrangementMapper;

    @Autowired
    private TaxiService taxiService;

    @Autowired
    private DriverScoreDeductingMapper driverScoreDeductingMapper;

    @Autowired
    private DriverScoreLogMapper driverScoreLogMapper;

    @Autowired
    private DriverRegionServiceArrangementLogic driverRegionServiceArrangementLogic;

    @Autowired
    private DriverMapper driverMapper;

    @Autowired
    private TaxiMapper taxiMapper;

    @Autowired
    private PrimaryCachePutter primaryCachePutter;

    @Autowired
    private RideOrderMapper rideOrderMapper;

    @Autowired
    private DriverRewardMapper driverRewardMapper;

    @Autowired
    private ScanRideOrderMapper scanRideOrderMapper;

    @Autowired
    private DriverRechargeMapper driverRechargeMapper;

    @Autowired
    private StreetRideOrderMapper streetRideOrderMapper;

    @Autowired
    private CancellationOrderMapper cancellationOrder;

    @Autowired
    private DriverMoneyDeductingMapper driverMoneyDeductingMapper;

    @Autowired
    private MemberRebateMapper memberRebateMapper;

    @Autowired
    private MemberMapper memberMapper;

    @Autowired
    private SimpleCallRideOrderMapper simpleCallRideOrderMapper;

    @Autowired
    private DriverWithdrawMapper driverWithdrawMapper;

    @Autowired
    private DriverFlowLogMapper driverFlowLogMapper;

    @Autowired
    private AdminDeductDriverScoreLogMongoRepository adminDeductDriverScoreLogMongoRepository;

    @Autowired
    ScoreDeductingLogLogic scoreDeductingLogLogic;

    @Override
    public RestResult<Page<ScoreDeductingPresenter>> getScoreDeductingList(AdminUser adminUser, ScoreDeductingQueryWrapper wrapper) {
        List<Driver> driverList = null;

        AdminUserIdentityPresenter identity = (AdminUserIdentityPresenter) adminUser.getIdentity();
        switch (adminUser.getAccountType()) {
            case canton:
                /*driverList = new LambdaQueryChainWrapper<>(driverMapper)
                        .select(Driver::getId)
                        .in(Driver::getCantonId, identity.getCantonIds())
                        .list();*/
                wrapper.setCantonIds(identity.getCantonIds());
                break;
            case company:
                /*List<Taxi> taxiList = new LambdaQueryChainWrapper<>(taxiMapper)
                        .select(Taxi::getId)
                        .in(Taxi::getCompanyId, identity.getCompanyIds())
                        .list();

                List<Long> taxiIds = taxiList.stream().map(Taxi::getId).collect(Collectors.toList());

                driverList = new LambdaQueryChainWrapper<>(driverMapper)
                        .select(Driver::getId)
                        .in(Driver::getTaxiId, taxiIds)
                        .list();*/
                wrapper.setCompanyIds(identity.getCompanyIds());
                break;
        }

        // 司机搜索
        if (Objects.nonNull(wrapper.getDriverSearch())) {
            if (this.isPhoneNum(wrapper.getDriverSearch())) {
                wrapper.setDriverMobilePhone(wrapper.getDriverSearch());

                wrapper.setDriverSearch(null);
                wrapper.setDriverName(null);
            } else {
                wrapper.setDriverName(wrapper.getDriverSearch());

                wrapper.setDriverSearch(null);
                wrapper.setDriverMobilePhone(null);
            }
        }

        Page<ScoreDeductingPresenter> res = driverScoreDeductingMapper.getScoreDeductingList(wrapper);

        return RestResult.success(res);
    }

    @Override
    public RestResult<ScoreDeductingPresenter> getScoreDeducting(Long id) {
        ScoreDeductingPresenter res = driverScoreDeductingMapper.getScoreDeducting(id);

        return RestResult.success(res);
    }


    @Override
    @Transactional
    public RestResult scoreDeducting(AdminUser adminUser, ScoreDeductingCreateWrapper wrapper) {
        Driver driver = driverMapper.selectById(wrapper.getDriverId());
        if (ObjectUtils.isEmpty(driver)) {
            return RestResult.build(ResultEnum.NOT_FOUND);
        }

        if (driver.getMarkScore().compareTo(BigDecimal.ZERO) <= 0) {
            return RestResult.failed("操作失败，司机原始分数小于等于0分，不能再扣分");
        }

        // 需要扣除的分数
        BigDecimal reqDeductingScore = new BigDecimal(wrapper.getValue());

        // 扣除之后的分数
        BigDecimal deductedScore = driver.getMarkScore().subtract(reqDeductingScore);

        if (deductedScore.compareTo(BigDecimal.ZERO) < 0) {
            return RestResult.failed("操作失败，扣除后司机分数将小于0分");
        }

        log.info(String.format("司机原始分数:[%f]", driver.getMarkScore()));
        log.info(String.format("司机扣除分数:[%f]", reqDeductingScore));
        log.info(String.format("司机设置新的分数:[%f]", deductedScore));

        log.info("司机扣分-司机:{}", driver);
        log.info("司机扣分-详情:{}", wrapper);

        // 判断是否为新版扣分
        Boolean isOpen = driverRegionServiceArrangementLogic.isOpen(driver.getDriverRegionId(), DriverRegionServiceArrangementCategory.driver_mark);
        DriverScoreDeducting deduction = new DriverScoreDeducting();

        if (isOpen) {
            // 新版扣分
            log.info("检测存在新版评价分配置，开始执行");
            wrapper.setStartedAt(new DateTime());

            // 扣分记录
            deduction.setDriverId(driver.getId());
            deduction.setDeduction(wrapper.getValue());
            deduction.setCategory(DriverScoreDeductingCategory.administrators);
            deduction.setStartedAt(wrapper.getStartedAt());
            deduction.setEndedAt(wrapper.getEndedAt());
            deduction.setDetail(wrapper.getDetail());

            driverScoreDeductingMapper.insert(deduction);

            // 分数记录
            DriverScoreLog driverScoreLog = new DriverScoreLog();
            driverScoreLog.setDriverId(driver.getId());
            driverScoreLog.setInOut(DriverScoreLogInOut.deduct);
            driverScoreLog.setCategory(DriverScoreLogCategory.score_deduct);
            // 这里是相反数
            driverScoreLog.setScore(reqDeductingScore.negate());
            driverScoreLog.setRefId(deduction.getId());
            driverScoreLog.setIsAvailable(true);
            driverScoreLog.setStartAt(wrapper.getStartedAt());

            driverScoreLogMapper.insert(driverScoreLog);
            log.info(String.format("司机原始分数:[%f]", driver.getMarkScore()));
            log.info(String.format("司机扣除分数:[%f]", reqDeductingScore));
            log.info(String.format("司机设置新的分数:[%f]", deductedScore));

            // 司机扣分
            Driver updateDriver = new Driver();
            updateDriver.setId(driver.getId());
            updateDriver.setMarkScore(deductedScore);
            updateDriver.setUpdatedAt(new Date());

            driverMapper.updateById(updateDriver);
        } else {
            // 旧版扣分
            log.info("未检测到存在新版评价分配置，开始旧的扣分逻辑");

            deduction.setDriverId(driver.getId());
            deduction.setDeduction(wrapper.getValue());
            deduction.setCategory(DriverScoreDeductingCategory.administrators);
            deduction.setStartedAt(wrapper.getStartedAt());
            deduction.setEndedAt(wrapper.getEndedAt());
            deduction.setDetail(wrapper.getDetail());

            driverScoreDeductingMapper.insert(deduction);
        }

        log.info("开始记录操作记录");

        AdminDeductDriverScoreLogMongo mongoLog = new AdminDeductDriverScoreLogMongo();
        mongoLog.setDriver_id(driver.getId());
        mongoLog.setDriver_name(driver.getName());
        mongoLog.setDriver_mobile_number(driver.getMobileNumber());
        mongoLog.setAdmin_id(adminUser.getId());
        mongoLog.setAdmin_account(adminUser.getAccount());
        mongoLog.setAdmin_name(adminUser.getName());
        mongoLog.setAdmin_mobile_number(adminUser.getMobileNumber());
        mongoLog.setDriver_score_deducting_id(deduction.getId());
        mongoLog.setDeduction(deduction.getDeduction());
        mongoLog.setDetail(deduction.getDetail());

        long intStartedAt = deduction.getStartedAt().getTime() / 1000;
        long intEndedAt = deduction.getEndedAt().getTime() / 1000;
        mongoLog.setStarted_at((int) intStartedAt);
        mongoLog.setEnded_at((int) intEndedAt);

        long now = new Date().getTime() / 1000;
        mongoLog.setCreated_at((int) now);

        adminDeductDriverScoreLogMongoRepository.insert(mongoLog);

        log.info("操作记录成功");
        log.info("开始刷新司机分数-远程接口");
        taxiService.refreshDriverScore(driver.getId());
        log.info("司机分数刷新完成");

        return RestResult.success();
    }

    @Override
    public RestResult<PageImpl<AdminDeductDriverScoreLogMongo>> scoreDeductingLog(ScoreDeductingLogQueryWrapper queryWrapper) {
        String adminSearch = queryWrapper.getAdminSearch();
        String driverSearch = queryWrapper.getDriverSearch();

        ScoreDeductingLogQueryDto queryDto = new ScoreDeductingLogQueryDto();

        // 管理员搜索
        if (Objects.nonNull(adminSearch)) {
            if (this.isPhoneNum(adminSearch)) {
                queryDto.setAdminPhone(adminSearch);
            } else {
                queryDto.setAdminName(adminSearch);
            }
        }

        // 司机搜索
        if (Objects.nonNull(driverSearch)) {
            if (this.isPhoneNum(driverSearch)) {
                queryDto.setDriverPhone(driverSearch);
            } else {
                queryDto.setDriverName(driverSearch);
            }
        }

        queryDto.setCurrent(queryWrapper.getCurrent() - 1);
        queryDto.setSize(queryWrapper.getSize());

        PageImpl<AdminDeductDriverScoreLogMongo> list = scoreDeductingLogLogic.getList(queryDto);

        return RestResult.success(list);
    }

    private Boolean isPhoneNum(String content) {
        return ReUtil.isMatch("^1[0-9]\\d{9}$", content);
    }
}
